package com.hj.springframework3.jdbc;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author : hujing
 * @Date: 2025/7/10 10:27
 * @Description: 将数据库查询结果映射到Java对象
 */
public class BeanRowMapper<T> implements RowMapper<T> {

    final Logger logger = LoggerFactory.getLogger(getClass());

    Class<T> clazz;
    Constructor<T> constructor;
    Map<String, Field> fileds = new HashMap<>();
    Map<String, Method> methods = new HashMap<>();

    public BeanRowMapper(Class<T> clazz) {
        this.clazz = clazz;
        try {
            // 获取无参的构造函数
            constructor = clazz.getConstructor();
        } catch (Exception e) {
            throw new IllegalArgumentException("没有默认的构造函数");
        }
        // 获取所有public属性
        for (Field field : clazz.getFields()) {
            String name = field.getName();
            this.fileds.put(name, field);
        }
        // 获取所有public方法
        for (Method method : clazz.getMethods()) {
            Parameter[] ps = method.getParameters();
            if (ps.length == 1) {
                String name = method.getName();
                if (name.length() >= 4 && name.startsWith("set")) {
                    // 获取属性名，比如setAge,则属性名为age
                    String prop = Character.toLowerCase(name.charAt(3)) + name.substring(4);
                    methods.put(prop, method);
                }
            }
        }
    }

    @Override
    public T mapRow(ResultSet rs, int rowNum) throws SQLException {
        T bean;
        try {
            bean = constructor.newInstance();
            ResultSetMetaData meta = rs.getMetaData();
            int columnCount = meta.getColumnCount();
            for (int i = 1; i <= columnCount; i++) {
                String label = meta.getColumnLabel(i);
                Method method = this.methods.get(label);
                if (method != null) {
                    method.invoke(bean, rs.getObject(label));
                } else {
                    Field field = this.fileds.get(label);
                    if (field != null) {
                        field.set(bean, rs.getObject(label));
                    }
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return bean;
    }
}
